/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.seam.forge.parser.java.impl;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.jboss.seam.forge.parser.JavaParser;
import org.jboss.seam.forge.parser.java.Annotation;
import org.jboss.seam.forge.parser.java.JavaClass;
import org.jboss.seam.forge.parser.java.JavaSource;
import org.jboss.seam.forge.parser.java.Method;
import org.jboss.seam.forge.parser.java.Parameter;
import org.jboss.seam.forge.parser.java.Visibility;
import org.jboss.seam.forge.parser.java.ast.AnnotationAccessor;
import org.jboss.seam.forge.parser.java.ast.ModifierAccessor;
/**
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class MethodImpl<O extends JavaSource<O>> implements Method<O>
{
private final AnnotationAccessor<O, Method<O>> annotations = new AnnotationAccessor<O, Method<O>>();
private final ModifierAccessor modifiers = new ModifierAccessor();
private O parent = null;
private AST ast = null;
private CompilationUnit cu = null;
private final MethodDeclaration method;
private void init(final O parent)
{
this.parent = parent;
cu = (CompilationUnit) parent.getInternal();
ast = cu.getAST();
}
public MethodImpl(final O parent)
{
init(parent);
method = ast.newMethodDeclaration();
method.setConstructor(false);
}
public MethodImpl(final O parent, final Object internal)
{
init(parent);
method = (MethodDeclaration) internal;
}
public MethodImpl(final O parent, final String method)
{
init(parent);
String stub = "public class Stub { " + method + " }";
JavaClass temp = (JavaClass) JavaParser.parse(stub);
List<Method<JavaClass>> methods = temp.getMethods();
MethodDeclaration newMethod = (MethodDeclaration) methods.get(0).getInternal();
MethodDeclaration subtree = (MethodDeclaration) ASTNode.copySubtree(cu.getAST(), newMethod);
this.method = subtree;
}
/*
* Annotation<O> Modifiers
*/
@Override
public Annotation<O> addAnnotation()
{
return annotations.addAnnotation(this, method);
}
@Override
public Annotation<O> addAnnotation(final Class<? extends java.lang.annotation.Annotation> clazz)
{
if (!parent.hasImport(clazz))
{
parent.addImport(clazz);
}
return annotations.addAnnotation(this, method, clazz.getSimpleName());
}
@Override
public Annotation<O> addAnnotation(final String className)
{
return annotations.addAnnotation(this, method, className);
}
@Override
public List<Annotation<O>> getAnnotations()
{
return annotations.getAnnotations(this, method);
}
@Override
public boolean hasAnnotation(final Class<? extends java.lang.annotation.Annotation> type)
{
return annotations.hasAnnotation(this, method, type.getName());
}
@Override
public boolean hasAnnotation(final String type)
{
return annotations.hasAnnotation(this, method, type);
}
@Override
public Method<O> removeAnnotation(final Annotation<O> annotation)
{
return annotations.removeAnnotation(this, method, annotation);
}
@Override
public Annotation<O> getAnnotation(final Class<? extends java.lang.annotation.Annotation> type)
{
return annotations.getAnnotation(this, method, type);
}
@Override
public Annotation<O> getAnnotation(final String type)
{
return annotations.getAnnotation(this, method, type);
}
/*
* Method<O> Modifiers
*/
@Override
@SuppressWarnings("unchecked")
public String getBody()
{
String result = "";
List<Statement> statements = (List<Statement>) method.getBody().getStructuralProperty(Block.STATEMENTS_PROPERTY);
for (Statement statement : statements)
{
result += statement + " ";
}
return result;
}
@Override
public Method<O> setBody(final String body)
{
String stub = "public class Stub { public void method() {" + body + "} }";
JavaClass temp = (JavaClass) JavaParser.parse(stub);
List<Method<JavaClass>> methods = temp.getMethods();
Block block = ((MethodDeclaration) methods.get(0).getInternal()).getBody();
block = (Block) ASTNode.copySubtree(method.getAST(), block);
method.setBody(block);
return this;
}
@Override
public Method<O> setConstructor(final boolean constructor)
{
method.setConstructor(constructor);
if (isConstructor())
{
method.setName(ast.newSimpleName(parent.getName()));
}
return this;
}
@Override
public boolean isConstructor()
{
return method.isConstructor();
}
@Override
public String getReturnType()
{
String result = null;
if (!isConstructor() && (method.getReturnType2() != null))
{
result = method.getReturnType2().toString();
}
return result;
}
@Override
public Method<O> setReturnType(final Class<?> type)
{
return setReturnType(type.getSimpleName());
}
@Override
public Method<O> setReturnType(final String typeName)
{
String stub = "public class Stub { public " + typeName + " method() {} }";
JavaClass temp = (JavaClass) JavaParser.parse(stub);
List<Method<JavaClass>> methods = temp.getMethods();
Type returnType = ((MethodDeclaration) methods.get(0).getInternal()).getReturnType2();
returnType = (Type) ASTNode.copySubtree(method.getAST(), returnType);
method.setReturnType2(returnType);
return this;
}
@Override
public boolean isReturnTypeVoid()
{
return getReturnType() == null;
}
@Override
public Method<O> setReturnTypeVoid()
{
method.setReturnType2(null);
return this;
}
/*
* Abstract Modifiers
*/
@Override
public boolean isAbstract()
{
return modifiers.hasModifier(method, ModifierKeyword.ABSTRACT_KEYWORD);
}
@Override
public Method<O> setAbstract(final boolean abstrct)
{
if (abstrct)
{
modifiers.addModifier(method, ModifierKeyword.ABSTRACT_KEYWORD);
}
else
{
modifiers.removeModifier(method, ModifierKeyword.ABSTRACT_KEYWORD);
}
return this;
}
@Override
public Method<O> setFinal()
{
modifiers.addModifier(method, ModifierKeyword.FINAL_KEYWORD);
return this;
}
@Override
public String getName()
{
return method.getName().getFullyQualifiedName();
}
@Override
public Method<O> setName(final String name)
{
if (method.isConstructor())
{
throw new IllegalStateException("Cannot set the name of a constructor.");
}
method.setName(ast.newSimpleName(name));
return this;
}
@Override
@SuppressWarnings("unchecked")
public Method<O> setParameters(final String parameters)
{
String stub = "public class Stub { public void method( " + parameters + " ) {} }";
JavaClass temp = (JavaClass) JavaParser.parse(stub);
List<Method<JavaClass>> methods = temp.getMethods();
List<VariableDeclaration> astParameters = ((MethodDeclaration) methods.get(0).getInternal()).parameters();
method.parameters().clear();
for (VariableDeclaration declaration : astParameters)
{
VariableDeclaration copy = (VariableDeclaration) ASTNode.copySubtree(method.getAST(), declaration);
method.parameters().add(copy);
}
return this;
}
@Override
@SuppressWarnings("unchecked")
public List<Parameter> getParameters()
{
List<Parameter> results = new ArrayList<Parameter>();
List<VariableDeclaration> parameters = method.parameters();
for (VariableDeclaration param : parameters)
{
results.add(new ParameterImpl(param));
}
return results;
}
/*
* Visibility Modifiers
*/
@Override
public boolean isPackagePrivate()
{
return (!isPublic() && !isPrivate() && !isProtected());
}
@Override
public Method<O> setPackagePrivate()
{
modifiers.clearVisibility(method);
return this;
}
@Override
public boolean isPublic()
{
return modifiers.hasModifier(method, ModifierKeyword.PUBLIC_KEYWORD);
}
@Override
public Method<O> setPublic()
{
modifiers.clearVisibility(method);
modifiers.addModifier(method, ModifierKeyword.PUBLIC_KEYWORD);
return this;
}
@Override
public boolean isPrivate()
{
return modifiers.hasModifier(method, ModifierKeyword.PRIVATE_KEYWORD);
}
@Override
public Method<O> setPrivate()
{
modifiers.clearVisibility(method);
modifiers.addModifier(method, ModifierKeyword.PRIVATE_KEYWORD);
return this;
}
@Override
public boolean isProtected()
{
return modifiers.hasModifier(method, ModifierKeyword.PROTECTED_KEYWORD);
}
@Override
public Method<O> setProtected()
{
modifiers.clearVisibility(method);
modifiers.addModifier(method, ModifierKeyword.PROTECTED_KEYWORD);
return this;
}
@Override
public Visibility getVisibility()
{
return Visibility.getFrom(this);
}
@Override
public Method<O> setVisibility(final Visibility scope)
{
return Visibility.set(this, scope);
}
/*
* Interfaces
*/
@Override
public String toString()
{
return method.toString();
}
@Override
public Object getInternal()
{
return method;
}
@Override
public O getOrigin()
{
return parent.getOrigin();
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((method == null) ? 0 : method.hashCode());
return result;
}
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
MethodImpl<?> other = (MethodImpl<?>) obj;
if (method == null)
{
if (other.method != null)
{
return false;
}
}
else if (!method.equals(other.method))
{
return false;
}
return true;
}
}